package com.wocai.jrt.admin.user.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.inject.Inject;
import javax.inject.Named;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.vteba.common.exception.BasicException;
import com.vteba.common.exception.ServiceException;
import com.vteba.security.user.Authority;
import com.vteba.service.generic.impl.MyBatisServiceImpl;
import com.vteba.tx.jdbc.mybatis.spi.BaseDao;
import com.vteba.utils.id.ObjectId;
import com.vteba.utils.json.FastJsonUtils;
import com.wocai.jrt.admin.common.bean.Icon;
import com.wocai.jrt.admin.common.bean.Node;
import com.wocai.jrt.admin.common.bean.State;
import com.wocai.jrt.admin.common.cache.Const;
import com.wocai.jrt.admin.user.dao.AuthoritiesDao;
import com.wocai.jrt.admin.user.dao.ModuleMenuDao;
import com.wocai.jrt.admin.user.model.AuthResource;
import com.wocai.jrt.admin.user.model.Authorities;
import com.wocai.jrt.admin.user.model.AuthoritiesBean;
import com.wocai.jrt.admin.user.model.ModuleMenu;
import com.wocai.jrt.admin.user.model.Resources;
import com.wocai.jrt.admin.user.model.RoleAuth;
import com.wocai.jrt.admin.user.model.Roles;
import com.wocai.jrt.admin.user.service.spi.AuthResourceService;
import com.wocai.jrt.admin.user.service.spi.AuthoritiesService;
import com.wocai.jrt.admin.user.service.spi.ResourcesService;
import com.wocai.jrt.admin.user.service.spi.RoleAuthService;
import com.wocai.jrt.orgadmin.utils.UserUtils;

/**
 * 权限表相关的service业务实现。
 * @author yinlei
 * @date 2015-7-6 11:40:41
 */
@Named
public class AuthoritiesServiceImpl extends MyBatisServiceImpl<Authorities, AuthoritiesBean, String> implements AuthoritiesService, com.vteba.security.spi.AuthoritiesService {
	private static final Logger LOGGER = LoggerFactory.getLogger(AuthoritiesServiceImpl.class);
	
	private AuthoritiesDao authoritiesDao;
	
	@Inject
	private AuthResourceService authResourceServiceImpl;
	
	@Inject
	private RoleAuthService roleAuthServiceImpl;
	
	@Inject
	private ResourcesService resourcesServiceImpl;
	
	@Inject
	private ModuleMenuDao moduleMenuDao;
	
	@Override
	@Inject
	public void setBaseDao(BaseDao<Authorities, AuthoritiesBean, String> authoritiesDao) {
		this.baseDao = authoritiesDao;
		this.authoritiesDao = (AuthoritiesDao) authoritiesDao;
	}

	@Override
	public List<Authorities> getAuthorities() {
//		List<String> authoritiesList = redisService.get(Const.AUTH_ALL);
//		if (authoritiesList == null || authoritiesList.size() == 0) {
//			authoritiesList = new ArrayList<>();
//			Authorities params = new Authorities();
//			params.setEnabled(1);
//			List<Authorities> authList = queryList(params);
//			for (Authorities auth : authList) {
//				authoritiesList.add(auth.getAuthName());
//			}
//			redisService.set(Const.AUTH_ALL, authoritiesList);
//		}
		//List<String> authoritiesList = new ArrayList<>();
		Authorities params = new Authorities();
		params.setEnabled(1);
		params.setState(0); // 查询机构的
		List<Authorities> authList = queryList(params);
		return authList;
//		for (Authorities auth : authList) {
//			authoritiesList.add(auth.getAuthName());
//		}
//		return authoritiesList;
	}

	@Override
	public List<Resources> getUrlResource(Authority authority) {
//		List<String> authoritiesList = redisService.get(Const.AUTH + authName);
//		if (authoritiesList == null || authoritiesList.size() == 0) {
//			authoritiesList = new ArrayList<>();
//			List<Resources> resourceList = resourcesServiceImpl.queryListByAuthName(authName);
//			for (Resources model : resourceList) {
//				authoritiesList.add(model.getResourceUrl());
//			}
//			redisService.set(Const.AUTH + authName, authoritiesList);
//		}
//		return authoritiesList;
		//List<String> authoritiesList = new ArrayList<>();
		List<Resources> resourceList = resourcesServiceImpl.queryListByAuth((Authorities) authority);
		return resourceList;
//		for (Resources model : resourceList) {
//			authoritiesList.add(model.getResourceUrl());
//		}
//		return authoritiesList;
	}

	@Override
	public List<Resources> getMethodResource(Authority authority) {
		// 这个还没有用到
		return Collections.emptyList();
	}

	@Override
	public List<Authorities> queryAuthorityList(String userId, String orgId) {
		return authoritiesDao.queryAuthorityList(userId, orgId);
	}

	@Override
	public int saveAuthorities(Authorities authorities) {
		String authId = ObjectId.get().toString();
		authorities.setAuthId(authId);
		
		try {
			String urls = authorities.getUrls();
			LOGGER.info("资源id=[{}]", urls);
			
			// 不填写中文名了，使用权限名代替，其他地方显示名称时，使用的是authDesc
			authorities.setAuthDesc(authorities.getAuthName());
			int i = save(authorities);
			if (i <= 0) {
				return 0;
			}
			
			saveAuthResource(authId, urls);
		} catch (Exception e) {
			LOGGER.error("save authorities error, msg=[{}].", e.getMessage());
			throw new ServiceException("save authorities error.", e);
		}
		return 1;
	}

	/**
	 * 保存权限和资源之间的关系。保存失败，抛异常。
	 * @param authId 权限Id
	 * @param urls 待保存的资源ids
	 */
	private void saveAuthResource(String authId, String urls) {
		String[] resourceIds = StringUtils.split(urls, ",");
		if (ArrayUtils.isEmpty(resourceIds)) {
			LOGGER.warn("save authorities and resource's relation. is empty.");
		} else {
			LOGGER.info("save authorities and resource's relation.");
			for (String resourceId : resourceIds) {
				// 暂时先这么判，jstree把父节点也一起获取到了，去掉父节点
				if (resourceId.length() < Const.ID_LEN) {
					continue;
				}
				
				AuthResource authResource = new AuthResource();
				authResource.setId(ObjectId.get().toString());
				authResource.setAuthId(authId);
				authResource.setResourceId(resourceId);
				// 保存权限和资源的关联
				int j = authResourceServiceImpl.save(authResource);
				if (j <= 0) {
					LOGGER.error("save authorities success, but save relation error.");
					throw new ServiceException("save auth and resource relation error.");
				}
			}
		}
	}

	@Override
	public int deleteAuthorities(String authId) {
		try {
			int ret = deleteAuthResource(authId);
			if (ret >= 0) { // 之所以等于0，可能有些权限还没有关联资源
				int result = deleteById(authId);
				// 删掉了关系，但是没有删掉权限，抛异常，回滚
				if (ret > 0 && result <= 0) {
					throw new ServiceException("delete authorities and resources's relation error.");
				}
			}
		} catch (Exception e) {
			LOGGER.error("delete authorities error, authId=[{}], msg=[{}].", authId, e.getMessage());
			throw new ServiceException("delete authorities error.", e);
		}
		return 1;
	}

	/**
	 * 删除该权限所有的资源关系
	 * @param authId 权限id
	 * @return 删除的记录数
	 */
	private int deleteAuthResource(String authId) {
		AuthResource params = new AuthResource();
		params.setAuthId(authId);
		return authResourceServiceImpl.deleteBulks(params);
	}

	@Override
	public int updateAuthorities(Authorities authorities) {
		String urls = authorities.getUrls();
		
		try {
			String authId = authorities.getAuthId();
			// 1、删除原来的权限和资源之间的关系
			int ret = deleteAuthResource(authId);
			// 2、保存权限
			int u = updateById(authorities);
			// 旧的关系删除了，但是新保存权限错误，抛异常回滚
			if (ret > 0 && u <= 0) {
				LOGGER.error("delete relation success, but update authorities record's number is 0.");
				throw new ServiceException("delete relation success, but update authorities record's number is 0.");
			}
			// 资源不为空，需要维护和资源的关系
			if (StringUtils.isNotBlank(urls)) {
				// 3、维护新的权限和资源之间的关系
				saveAuthResource(authId, urls);
			}
//			else { // 没有资源，只更新权限的信息即可
//				int authRet = updateById(authorities);
//				if (authRet <= 0) {
//					LOGGER.warn("update authorities record's number is 0.");
//				}
//			}
		} catch (Exception e) {
			LOGGER.error("update authorities error.", e.getMessage());
			throw new ServiceException("update authorities error.", e);
		}
		return 1;
	}

	@Override
	public Node getAuthTree(Roles roles) {
		Node root = new Node();
		root.setId("-1");
		root.setText("角色权限");
		root.setIcon(Icon.BRIEF_WARN);
		try {
			// 以后缓存
			Authorities authParma = new Authorities();
			authParma.setOrgId(UserUtils.getOrgId());
			// 查询该机构的权限
			List<Authorities> authList = queryList(authParma);
			Set<String> authIdSet = new HashSet<String>();
			
			// 如果角色id不为空，查询该角色下的权限
			String roleId = roles.getRoleId();
			if (roleId != null && !roleId.equals("null")) {
				RoleAuth params = new RoleAuth();
				params.setRoleId(roleId);
				List<RoleAuth> roleAuthList = roleAuthServiceImpl.queryList(params);
				for (RoleAuth bean : roleAuthList) {
					authIdSet.add(bean.getAuthId());
				}
				// 根节点打开
				State state = new State();
				state.setOpened(true);
				root.setState(state);
			}
			
			// 获取该机构的菜单
			ModuleMenu menuParams = new ModuleMenu();
			menuParams.setOrgId(UserUtils.getOrgId());
			List<ModuleMenu> menuList = moduleMenuDao.queryList(menuParams);
			
			List<Node> menuNodeList = new ArrayList<>();
			// 构建tree的二级节点
			for (ModuleMenu menu : menuList) {
				Node menuNode = new Node();
				menuNode.setId(menu.getModuleId());
				menuNode.setText(menu.getModuleName());
				menuNode.setIcon(Icon.FILE_DANGER);
				menuNodeList.add(menuNode);
				
				// 判断是否禁用
				if (roles.getEnabled() != null && roles.getEnabled() == 0) {
					State state = new State();
					state.setLoaded(true);
					state.setDisabled(true);
					
					menuNode.setState(state);
				}
				
				for (Authorities auth : authList) {
					if (menu.getModuleId().equals(auth.getModuleId())) {
						Node authNode = new Node();
						String authId = auth.getAuthId();
						
						// 拥有这个权限
						if (authIdSet.contains(authId)) {
							State state = new State();
							state.setSelected(true);
							state.setLoaded(true);
							if (roles.getEnabled() != null && roles.getEnabled() == 0) {
								state.setDisabled(true);
							}
							authNode.setState(state);
						} else { // 没有这个权限
							State state = new State();
							state.setLoaded(true);
							if (roles.getEnabled() != null && roles.getEnabled() == 0) {
								state.setDisabled(true);
							}
							authNode.setState(state);
						}
						authNode.setId(authId);
						authNode.setText(auth.getAuthDesc());
						authNode.setIcon(Icon.FILE_DANGER);
						
						// 判断是否有子节点
						if (menuNode.getChildren() == null) {
							List<Node> nodeList = new ArrayList<Node>();
							menuNode.setChildren(nodeList);
						}
						menuNode.getChildren().add(authNode);
					}
				}
			}
			root.setChildren(menuNodeList);
		} catch (Exception e) {
			LOGGER.error("get authorities tree error, msg=[{}].", e.getMessage());
			throw new BasicException("get authorities tree error.", e);
		}
		
		if (LOGGER.isInfoEnabled()) {
			LOGGER.info("tree json =[{}].", FastJsonUtils.toJson(root));
		}
		
		return root;
	}
}
